﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Bioinformatics.Types;

namespace Bioinformatics.Controls
{
    public partial class PhylogenyDrawer : PictureBox
    {
        private float _bottomNodeY = 0.0f;
        public int MinimumBranchLength { get; set; }
        public int MinimumBranchSpacing { get; set; }
        
        public string NewickString { get; set; }
        
        public PhylogenyDrawer()
        {
            MinimumBranchLength = 10;
            MinimumBranchSpacing = 30;
            NewickString = "((A:1,B:1),(C:1,D:1))";
            InitializeComponent();
        }

        protected override void OnPaint(PaintEventArgs pe)
        {
            base.OnPaint(pe);
            pe.Graphics.DrawImage(RenderTree(),Padding.All,Padding.All);
        }

        private Bitmap RenderTree()
        {
            //create canvas
            var canvas = new Bitmap(Size.Width - Padding.All, Size.Height - Padding.All);
            var gfx = Graphics.FromImage(canvas);

            //clear the canvas
            gfx.Clear(BackColor);

            //convert the newick string into a binary tree
            var dynamicPhylogeny = new DynamicPhylogeny(NewickString);

            //complete a BFS to determine total amount of tree tips
            var nodeQueue = new Queue<DynamicPhylogenyNode>();
            nodeQueue.Enqueue(dynamicPhylogeny.Root);
            var tipCount = 0;

            while(nodeQueue.Count > 0)
            {
                //pop from queue
                var currentNode = nodeQueue.Dequeue();
                //check whether the current node has children if not, it is a tip
                if (currentNode.LeftChild != DynamicPhylogenyNode.TerminatorNode && currentNode.RightChild != DynamicPhylogenyNode.TerminatorNode)
                {
                    nodeQueue.Enqueue(currentNode.LeftChild);
                    nodeQueue.Enqueue(currentNode.RightChild);
                }
                else
                    tipCount++;
            }

            //deterimine spacing of branches
            MinimumBranchSpacing = canvas.Width/(tipCount + 2);

            CalculateChildPosition(dynamicPhylogeny.Root, new PointF(50, 50), gfx);

            return canvas;
        }

        private PointF CalculateChildPosition(DynamicPhylogenyNode node, PointF ancestorPosition, Graphics gfx)
        {
            var position = new PointF(node.BranchLength, 0);

            //recurse tree
            if (node.LeftChild != DynamicPhylogenyNode.TerminatorNode && node.RightChild != DynamicPhylogenyNode.TerminatorNode)
            {
                var leftPosition = CalculateChildPosition(node.LeftChild, position,gfx);
                var rightPosition = CalculateChildPosition(node.RightChild, position,gfx);
                position.Y = (leftPosition.Y + rightPosition.Y)/2;
                //draw vertical connector
                gfx.DrawLine(Pens.Black, ancestorPosition.X + position.X, leftPosition.Y, ancestorPosition.X + position.X, rightPosition.Y);
                //draw branch
                gfx.DrawLine(Pens.Black, ancestorPosition.X, position.Y, ancestorPosition.X + position.X, position.Y);
                return position;
            }
            //reached tips
            position.Y = _bottomNodeY;
            _bottomNodeY += MinimumBranchSpacing;
            //draw branch
            gfx.DrawLine(Pens.Black, ancestorPosition.X, position.Y, ancestorPosition.X + position.X, position.Y);
            return position;
        }

    }
}
